--[[
	操作auth 相关的redis和mysql的service
	核心表：rs_auth ,主键 uid:xxxx  字符串
]]
local filename = "opauth.lua"

local skynet = require "skynet"
require "skynet.manager"

local mysql = require "skynet.db.mysql"

local filelog = require "filelog"
local configdao = require "configdao"
local redisdao = require "redisdao"
local mysqldao = require "mysqldao"
local timetool = require "timetool"
local base = require "base"
local md5 = require "md5"
local math = require "math"
require "pubenum"

local CMD = {}
local redisdb
local mysqldb

local function check_table_keys(dbsql, dbstruct)
	local same_num, max_num = 0, 0
	if type(dbsql) ~= type{} or type(dbstruct) ~= type{} then
		filelog.sys_error("check_table_keys: not table")
		return false
	end
	for k, v in pairs(dbsql) do
		max_num = max_num + 1
		if dbstruct[k] then
			if type(v) == type{} then
				if not check_table_keys(dbsql[k], dbstruct[k]) then
					filelog.sys_error("check_table_keys: check failed 1, key is ", k, dbsql[k], dbstruct[k])
					return false
				end
			end
			same_num = same_num + 1
		else
			filelog.sys_error("check_table_keys: check failed 2 key :'" .. k .."' is not exist in luastruct")
			break
		end
	end
	if same_num == max_num then
		same_num, max_num = 0, 0
		for k, v in pairs(dbstruct) do
			max_num = max_num + 1
			if dbsql[k] then
				if type(v) == type{} then
					if not check_table_keys(dbsql[k], dbstruct[k]) then
						filelog.sys_error("check_table_keys: check failed 3, key is ", dbsql[k], dbstruct[k])
						return false
					end
				end
				same_num = same_num + 1
			else
				filelog.sys_error("check_table_keys: check failed 4 key :'" .. k .."' is not exist in mysql(db)")
				break
			end
		end
	end
	return same_num == max_num
end

local function checkdb_struct(dbs)
	local basetables = require "dbstruct"
	local tables = {}
	for k, v in pairs(basetables) do
		tables[k] = v.fields or v
		if k == "rs_user" or k == "rs_info" then
			tables[k].phonenum = 0
		end
	end

	local database = configdao.get_cfgsvrs_key("datamysql").database
	local dbtables = {}
	local res, tabledata = skynet.call(dbs, "lua", "query", true, "show tables;")
	if res then
		local name = "Tables_in_" .. database
		for _, v in ipairs(tabledata) do
			res, cols = skynet.call(dbs, "lua", "query", true, 
			'select column_name, column_type from information_schema.columns where table_name = "' .. v[name]
			.. '" and table_schema = "' .. database .. '";')
		
			if res then
				dbtables[v[name]] = {}
				for _, col in ipairs(cols) do
					dbtables[v[name]][col.column_name] = col.column_type
				end
			end
		end
	else
		return false
	end
	-- 暂时不检查数据库
	if not check_table_keys(dbtables, tables) then
		filelog.sys_error("\ncheckdb_struct failed!")
		-- skynet.abort()
		return false
	else
		print("\ncheckdb_struct cucceed!\n")
		return true
	end
	return false
end


function CMD.authwx(unionid, rolename, agencyrid, pkgid)
	local status, result, result_data, userdata
	local rid, username, cpass, newrole
	newrole = 1

	username = unionid
	agencyrid = tonumber(agencyrid) or 0

	status, result_data = mysqldao.select(mysqldb, "rs_user", "where username = " .. mysql.quote_sql_str(username) )
    if not status then
        return
	elseif #result_data == 0 then
		-- 没有这个用户，需要创建用户，创建新玩家
		status, rid = redisdao.query_data(".freeridredisdb", "SPOP", "freeridpool")
        if not status or not rid then
            return
        end
		cpass = md5.sumhexa(math.random(100000, 999999))
		userdata = {rid=rid, username=username, cpass=cpass, saltpass=md5.sumhexa(username .. cpass), guestmobileid="*" .. rid, gategroup=1, create_time = timetool.get_time()}
		result, result_data = mysqldao.sync_insert(mysqldb, "rs_user", _, userdata)
        if not result then
            return
        end
		userdata['create_time'] = timetool.get_time()
		newrole = 2
	else
		rid = result_data[1]["rid"]
		userdata = result_data[1]
	end

	-- 去游戏数据库查询创建新的 rs_info, 如果没有就创建
	result = skynet.call(".router", "lua", "select_rk", rid, "rs_info")
	
	local setargs = { }
	--更新角色名
	if rolename and rolename ~= "" and result[2][rid].rolename ~= rolename then
		setargs.rolename = rolename
	end
	--更新agencyrid 
	if tonumber(result[2][rid].agencyrid) == 0 and agencyrid > 0 then
		setargs.agencyrid = agencyrid
		userdata['agencyrid'] = agencyrid
	else
		userdata['agencyrid'] = tonumber(result[2][rid].agencyrid)
	end
	--更新包id
	if pkgid then
		setargs.pkgid = tonumber(pkgid)
	end
	if next(setargs) ~= nil then
		result = skynet.call(".router", "lua", "update_rk", rid, "rs_info", 0, setargs)
	end

	return {newrole, {userdata}} -- 2 说明是个新用户
end

function CMD.authother(username, cpass, pkgid)
	local status, result, result_data, userdata
	local rid, newrole
	newrole = 1

	status, result_data = mysqldao.select(mysqldb, "rs_user", "where username = " .. mysql.quote_sql_str(username) )
	if not status then
        return
	elseif #result_data == 0 then
		-- 没有这个用户，需要创建用户，创建新玩家
		status, rid = redisdao.query_data(".freeridredisdb", "SPOP", "freeridpool")
        if not status or not rid then
            return
        end
		userdata = {rid=rid, username=username, cpass=cpass, saltpass=md5.sumhexa(username .. cpass), guestmobileid="*" .. rid, gategroup=1, create_time = timetool.get_time()}
		result, result_data = mysqldao.sync_insert(mysqldb, "rs_user", _, userdata)
        if not result then
            return
        end
		userdata['create_time'] = timetool.get_time()
		newrole = 2
	else
		rid = result_data[1]["rid"]
		userdata = result_data[1]
	end

	-- 去游戏数据库查询创建新的 rs_info, 如果没有就创建
	result = skynet.call(".router", "lua", "select_rk", rid, "rs_info")
	
    local setargs = { }

	--更新角色名
	if result and result[2][rid].rolename ~= username and username ~= "" then
		setargs.rolename = username
	end
	--包id
	if pkgid then
		setargs.pkgid = tonumber(pkgid)
	end
    if next(setargs) ~= nil then
		result = skynet.call(".router", "lua", "update_rk", rid, "rs_info", 0, setargs)
	end

	return {newrole, {userdata}} -- 2 说明是个新用户
end

function CMD.authuser(username, cpass)
	local status, result, result_data
	status, result_data = mysqldao.select(mysqldb, "rs_user", "where username = " .. mysql.quote_sql_str(username) .. " and saltpass='" .. md5.sumhexa(username .. cpass) .. "'")
	if not status then
        return
	elseif #result_data == 0 then
		return {0, {}}
	else
		return {1,result_data}
	end
end

function CMD.authphone(phonenum, phonecpass, issignin, rolename, agencyrid, pkgid)
	local newrole = 1
	local rid, username, cpass, userdata
	local status, result, result_data
	
	phonenum = tostring(phonenum) or ""
	agencyrid = tonumber(agencyrid) or 0
	pkgid = tonumber(pkgid) or 0
	
	status, result_data = mysqldao.select(mysqldb, "rs_user", "where phonenum = " .. mysql.quote_sql_str(phonenum) )
	if not status then
        return
	elseif #result_data == 0 then
		if not issignin then
			return
		end
		
		-- 没有这个用户，需要创建用户，创建新玩家
		status, rid = redisdao.query_data(".freeridredisdb", "SPOP", "freeridpool")
        if not status or not rid then
            return
        end
		username = "p" .. rid
		cpass = md5.sumhexa(math.random(100000, 999999))
		userdata = {
			rid = rid, username = username, cpass = cpass, 
			saltpass = md5.sumhexa(username .. cpass), guestmobileid = "*" .. rid, 
			gategroup = 1, phonenum = phonenum, phonecpass = cpass, 
			phonesaltpass = md5.sumhexa(phonenum .. cpass),
			create_time = timetool.get_time(),
		}
		result, result_data = mysqldao.sync_insert(mysqldb, "rs_user", _, userdata)
        if not result then
            return
        end
		userdata['create_time'] = timetool.get_time()
		newrole = 2
	else
		rid = result_data[1]['rid']
		userdata = result_data[1]
	end
	
	-- 去游戏数据库查询创建新的 rs_info, 如果没有就创建
	result = skynet.call(".router", "lua", "select_rk", rid, "rs_info")
		
	local setargs = { }
	--更新角色名
	if rolename and rolename ~= "" and result[2][rid].rolename ~= rolename then
		setargs.rolename = rolename
	end
	--更新agencyrid 
	if agencyrid and tonumber(result[2][rid].agencyrid) == 0 and agencyrid > 0 then
		setargs.agencyrid = agencyrid
		userdata['agencyrid'] = agencyrid
	else
		userdata['agencyrid'] = tonumber(result[2][rid].agencyrid)
	end
	--包id
	if pkgid then
		setargs.pkgid = tonumber(pkgid)
	end
	--更新手机号
	if newrole == 2 and result[2][rid].phonenum ~= phonenum then
		setargs.phonenum = phonenum
	end
	if next(setargs) ~= nil then
		result = skynet.call(".router", "lua", "update_rk", rid, "rs_info", 0, setargs)
	end

	return {newrole, {userdata}} -- 2 说明是个新用户
end

function CMD.authguest(randmobileid, sex, logo, pkgid)
	local status, result, result_data, userdata
	local rid, username, cpass
    local newrole = 1   --1旧用户 2新用户

	status, result_data = mysqldao.select(mysqldb, "rs_user", "where guestmobileid = " .. mysql.quote_sql_str(randmobileid))
	if not status then
        return
	elseif #result_data == 0 then
		-- 没有这个用户，需要创建用户，创建新玩家
		status, rid = redisdao.query_data(".freeridredisdb", "SPOP", "freeridpool")
        if not status or not rid then
            return
        end
		username = "_g" .. rid
		cpass = md5.sumhexa(math.random(100000, 999999))
		userdata = {rid=rid, username=username, cpass=cpass, saltpass=md5.sumhexa(username .. cpass), guestmobileid=randmobileid, gategroup=1 ,create_time = timetool.get_time()}
		result, result_data = mysqldao.sync_insert(mysqldb, "rs_user", _, userdata)
        if not result then
            return
        end
        userdata['create_time'] = timetool.get_time()
		newrole = 2
	else
		rid = result_data[1]["rid"]
		userdata = result_data[1]
	end

    -- 去游戏数据库查询创建新的 rs_info, 如果没有就创建
	result = skynet.call(".router", "lua", "select_rk", rid, "rs_info")

    local setargs = { }

    --更新角色名
	if result and result[2][rid].rolename ~= username then
		setargs.rolename = username
	end
    --新用户更新性别和头像
    if result and  newrole == 2 and result[2][rid] then
        setargs.sex = sex
        setargs.logo = logo
    end
	--包id
	if pkgid then
		setargs.pkgid = tonumber(pkgid)
	end
    if next(setargs) ~= nil then
		result = skynet.call(".router", "lua", "update_rk", rid, "rs_info", 0, setargs)
	end

	return {newrole, {userdata}} -- 2 说明是个新用户
end

--检测是否是新用户
function CMD.check_is_newuser(authtype, username)
    local status,result_data
    if authtype == "authwx" then
        status, result_data = mysqldao.select(mysqldb, "rs_user", "where username = " .. mysql.quote_sql_str(username) )
    elseif authtype == "authother" then
        status, result_data = mysqldao.select(mysqldb, "rs_user", "where username = " .. mysql.quote_sql_str(username) )
    elseif authtype == "authguest" then
        status, result_data = mysqldao.select(mysqldb, "rs_user", "where guestmobileid = " .. mysql.quote_sql_str(username))
    else
        return false
    end
    if status and #result_data == 0 then
        return true
    end

    return false
end

-- 有返回rid，没有返回0
-- 按次序从redis，mysql中读取，msyql读取成功后，写入redis
-- 加入了gategroup这样一个字段，redis里面的存储变成了： rid_gategroup 的字符串
function CMD.getridbyuid(uid)
	local status, result_data
	local authkey = "uid:" .. uid

	status, result_data = redisdao.query_data(redisdb, "get", authkey)
	if result_data then
		return base.strsplit(result_data, "_")
	end
	-- redis中没有获得，则从数据库中获取
	status, result_data = mysqldao.select(mysqldb, "rs_auth", "where uid =" .. uid)
	if #result_data == 0 then
		return {0, 0}
	end
	local result_str = result_data[1]["rid"] .. "_" .. result_data[1]["gategroup"]
	redisdao.query_data(redisdb, "set", authkey, result_str)
	return {result_data[1]["rid"], result_data[1]["gategroup"]}
end

-- 绑定uid，rid的对应关系
-- 成功返回1，  失败返回0
-- 插入数据库，写入redis
function CMD.newauthrid(uid, rid)
	local result, result_data
	local authkey = "uid:" .. uid

	result, result_data = mysqldao.sync_insert(mysqldb, "rs_auth", _, {uid=uid, rid=rid, create_time = timetool.get_time()})
	if result_data.err then
		-- 插入失败
		filelog.sys_error(filename.." CMD:newauthrid@" ..result_data.err .. "| rs_auth | uid=" .. uid .. ", rid=" .. rid)
		return 0
	end
	redisdao.query_data(redisdb, "set", authkey, rid .. "_1")
	return 1
end

--ranktype 1房卡 2金豆 3金币
function CMD.newrank(ranktype, linenum)
	linenum = linenum or 10

    local sqlstr = ""
    if ranktype == ERankType.DIAMOND then
        sqlstr = "select  rs_info.rid, rolename, level, logo, sex, intro, agencyrid,agencylevel,fangka, diamond as alldiamond from rs_money, rs_info where rs_money.rid=rs_info.rid order by diamond desc limit " .. linenum
    elseif ranktype == ERankType.COIN then
        sqlstr = "select  rs_info.rid, rolename, level, logo, sex, intro, agencyrid,agencylevel,fangka, coin as alldiamond from rs_money, rs_info where rs_money.rid=rs_info.rid order by coin desc limit " .. linenum
	elseif ranktype == ERankType.PROP then
        sqlstr = "select  rs_info.rid, rolename, level, logo, sex, intro, agencyrid,agencylevel, maxscore as alldiamond from rs_drresult, rs_info where rs_drresult.rid=rs_info.rid order by maxscore desc limit " .. linenum
	elseif ranktype == ERankType.MINIGAME_BEATER then
        sqlstr = "select  rs_info.rid, rolename, level, logo, sex, intro, agencyrid,agencylevel, maxscore as alldiamond from rs_ddsresult, rs_info where rs_ddsresult.rid=rs_info.rid order by maxscore desc limit " .. linenum
	elseif ranktype == ERankType.MINIGAME_SHOOTER then
        sqlstr = "select  rs_info.rid, rolename, level, logo, sex, intro, agencyrid,agencylevel, maxscore as alldiamond from rs_dfjresult, rs_info where rs_dfjresult.rid=rs_info.rid order by maxscore desc limit " .. linenum
	elseif ranktype == ERankType.MINIGAME_LINKER then
        sqlstr = "select  rs_info.rid, rolename, level, logo, sex, intro, agencyrid,agencylevel, maxscore as alldiamond from rs_llkresult, rs_info where rs_llkresult.rid=rs_info.rid order by maxscore desc limit " .. linenum
	end
	result, result_data = mysqldao.query(mysqldb, sqlstr)
	if not result_data or result_data.err then
		filelog.sys_error("---newrank failed-----")
		result, result_data = mysqldao.query(mysqldb, sqlstr)
		if result_data.err then
			return {}
		end
	end
	return result_data
end

function CMD.init()
	-- 每个操作service，都有单独创建自己到redis，mysql的链接
	local authredis = configdao.get_cfgsvrs_key("authredis")
	if authredis ~= nil then
		redisdb = skynet.newservice("redisdb")
		skynet.call(redisdb, "lua", "init", authredis)
	end
	local datamysql = configdao.get_cfgsvrs_key("datamysql")
	if datamysql ~= nil then
		mysqldb = skynet.newservice("mysqldb")
		skynet.call(mysqldb, "lua", "init", datamysql)
	end
end

function CMD.checkdb()
	if not mysqldb then return false end
	return checkdb_struct(mysqldb)
end

skynet.start(function()
	local freeridredis = configdao.get_cfgsvrs_key("freeridredis")
	skynet.name(".freeridredisdb", skynet.newservice("redisdb") )
	skynet.call(".freeridredisdb", "lua", "init", freeridredis)


	skynet.dispatch("lua", function(session, address, cmd, ...)
		local f = CMD[cmd]
		if f then
			skynet.ret(skynet.pack(f(...)))
		else
			error(string.format("Unknown cmd %s", tostring(cmd)))
		end
	end)
end)